/*
Hermes Core: General Purpose Mobile Agent Platform
Copyright (C) 2006 UNICAM - Università degli Studi di Camerino

Group leaders: Flavio Corradini and Emanuela Merelli

Developers: Ezio Bartocci, Diego Bonura, Rosario Culmone,
Davide Lorenzoli, Leonardo Mariani, Francesca Piersigilli, 
Lorenzo Scortichini, Leonardo Vito.

GNU Lesser Public License

This library is free software; you can redistribute it 
and/or modify it under the terms of the GNU Lesser General 
Public License as published by the Free Software Foundation, 
version 2.1 of the License.

This library is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
See the GNU Library General Public License for more details.

You should have received a copy of the GNU Library General Public 
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.

Emanuela Merelli
Dipartimento di Matematica ed Informatica
Università di Camerino
via Madonna delle Carceri, 62032 Camerino, Italy
E.Mail: emanuela.merelli@unicam.it
*/
package hermesV2.basicServices.security;

import hermesV2.agent.Identificator;

import hermesV2.util.HermesLogger;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;


/**
 * This is the component that protects every serviceAgents from a not allowed communication.
 * Every time a new serviceAgent wants to be protected has to register into the SecurityManager component otherwise
 * every messages will pass.
 * If a serviceAgent is registered an agent must be login into the component to permit the message communication.
 *
 *
 * @author Diego Bonura
 *
 */
public class SecurityManager implements Security {
    /**
     * The synchronized HashMap that contains serviceAgents identificator plus userId and Passwd.
    */
    private HashMap<String, String> passwdHashMap;

    /**
     * The HashMap that contains serviceAgents identificator plus userId and Passwd.
    */
    private Map <String, String> passwdMap;

    /**
     * The synchronized HashMap that contains every agent logged into a single serviceAgent.
    */
    private HashMap<String,String> linksHashMap;

    /**
     * The HashMap that contains every agent logged into a single serviceAgent.
    */
    private Map<String, String>  linksMap;

    /**
     * The costructor of the SecurityManager.
     *
     *
     */
    public SecurityManager() {
        passwdHashMap = new HashMap<String, String> ();
        linksHashMap = new HashMap<String, String> ();
        passwdMap = Collections.synchronizedMap(passwdHashMap);
        linksMap = Collections.synchronizedMap(linksHashMap);
    }

    /**
     * It checks if an Agent has the permission to communicate with a serviceAgent.
     *
     *
     * @param agentIdentificator The agent identificator that wants to communicate.
     * @param serviceAgentIdentificator The receiver serviceAgent identificator.
     *
     * @return True if the communication is permitted, otherwise false.
     */
    public boolean checkLink(Identificator agentIdentificator, Identificator serviceAgentIdentificator) {
        boolean success=false;
    	if (passwdMap.get(serviceAgentIdentificator.toString()) == null) {
            HermesLogger.log(HermesLogger.DEBUG, "Message from agent: " + agentIdentificator + "+passed to service agent: " + serviceAgentIdentificator + " without autentication!");

            success=true;
        }

        if (linksMap.get(agentIdentificator.toString() + "&" + serviceAgentIdentificator.toString()) != null) {
            success=true;
        }

        return success;
    }

    /**
     * Registers a new serviceAgent into the component with a UserId and a Password.
     *
     * @param serviceAgentIdentificator the serviceAgent identificator that wants to register itself into the component.
     * @param userId the userId of the serviceAgent.
     * @param passwd the password of the serviceAgent.
     */
    public void registerServiceAgent(Identificator serviceAgentIdentificator, String userId, String passwd) {
        //Checks if the identificator is a service agent
        if (serviceAgentIdentificator.isServiceAgent()) {
            passwdMap.put(serviceAgentIdentificator.toString(), userId + ":" + passwd);
        } else {
            HermesLogger.log(HermesLogger.WARNING, "The agent: " + serviceAgentIdentificator + " has not a service agent identificator!");
        }
    }

    /**
    * Erases the registration of the serviceAgent into the component.
    *
    *
    * @param serviceAgentIdentificator the serviceAgent identificator to unregister into the SecurityManager component.
    *
    * @return True if the serviceAgent is unregistered successfully otherwise false (the serviceAgent was not registered).
    */
    public boolean unregisterServiceAgent(Identificator serviceAgentIdentificator) {
        boolean success;
    	if (passwdMap.remove(serviceAgentIdentificator.toString()) != null) {
            success=true;
        } else {
            success=false;
        }
    	return success;
    }

    /**
    * Offers the possibility to an agent to login into the component for a specific serviceAgentidentificator.
    *
    * @param agentIdentificator The agent identificator that wants to login to a specific serviceAgent.
    * @param serviceAgentIdentificator The serviceAgent identificator to login.
    * @param userId The userId of the serviceAgent.
    * @param passwd the password of the serviceAgent.
    *
    * @return True if the agent is logged otherwise false.
    */
    public boolean loginAgent(Identificator agentIdentificator, Identificator serviceAgentIdentificator, String userId, String passwd) {
        boolean success=false;
    	if (checkLink(agentIdentificator, serviceAgentIdentificator)) {
            success=true;
        } else {
            if (passwdMap.get(serviceAgentIdentificator.toString()) != null) {
                if (passwdMap.get(serviceAgentIdentificator.toString()).equals((userId + ":" + passwd))) {
                    linksMap.put(agentIdentificator.toString() + "&" + serviceAgentIdentificator.toString(), "allow");

                    success= true;
                }
            }
        }

        return success;
    }

    /**
      * logouts the agent from a specific serviceAgent.
      *
      * @param agentIdentificator The identificator of the agent that wants to logout from a specific serviceAgent.
      * @param serviceAgentIdentificator The identificator of the serviceAgent.
      *
      * @return true if the logout is ok, otherwise false.
      */
    public boolean logoutAgent(Identificator agentIdentificator, Identificator serviceAgentIdentificator) {
        boolean success;
    	if (linksMap.remove(agentIdentificator.toString() + "&" + serviceAgentIdentificator.toString()) != null) {
            success= true;
        } else {
            success= false;
        }
    	return success;
    }

    /**
             * Logouts the agent from every serviceAgent registered into the component.
             *
             * @param agentIdentificator the identificator of the agent that wants to logout from every serviceAgent.
             */
    public void logoutAgent(Identificator agentIdentificator) {
        	Set<String> linksSet = linksMap.keySet();
            Iterator<String> linksIterator = linksSet.iterator();
        
        while (linksIterator.hasNext()) {
        	String keyStr = linksIterator.next();
            
            String id = keyStr.substring(0, keyStr.indexOf("&"));

            if (id.equals(agentIdentificator.toString())) {
                linksMap.remove(keyStr);
                linksSet = linksHashMap.keySet();
                linksIterator = linksSet.iterator();
            }
            
        }
    }
}
